<!-- #layout name=default -->
<div id="main" class="fixed">
    <div class="page-header">
        <!-- ko if: isNewStyle -->
        <h1 class="title pull-left">Style</h1>
        <button data-bind="visible: styleContent, click: formatCode" type="button" class="btn btn-default pull-right">Format code</button>
        <div class="form-group">
            <input data-bind="value: name, error: name" type="text" placeholder="Name" class="form-control input-medium">
        </div>
        <!-- /ko -->
        <!-- ko ifnot: isNewStyle -->
        <h1 data-bind="text: Kooboo.text.site.style.name + ': '+ (name() || '')" class="title"></h1>
        <button data-bind="visible: styleContent && curType() == 'raw', click: formatCode" type="button" class="btn btn-default pull-right">Format code</button>
        <!-- /ko -->
    </div>
    <div class="block-fullpage with-buttons">
        <div class="block-style-editor-v2 default">
            <div class="tabs-bottom">
                <div class="tab-content">
                    <div data-bind="css:{'active':curType()=='raw'}" class="tab-pane">
                        <textarea data-bind="codeMirror: {
                            mode: 'css',
                            value: styleContent,
                        }"></textarea>
                    </div>
                    <div data-bind="css:{'active':curType()=='fmt'}" class="tab-pane">
                        <div data-bind="component: { 
                            name: 'kb-style-set', 
                            params: { 
                                rules: rules(), 
                                getRules: getModifiedRules
                            }
                        }"></div>
                    </div>
                </div>
                <ul class="nav nav-tabs">
                    <li data-bind="css:{'active':curType()=='raw' }, click: changeType.bind(this, 'raw')">
                        <a href="javascript:;">Source code</a>
                    </li>
                    <li data-bind="css:{'active':curType()=='fmt' }, click: changeType.bind(this, 'fmt')">
                        <a href="javascript:;">Formated</a>
                    </li>
                    <li class="pull-right" data-bind="visible: curType() == 'fmt'">
                        <!-- ko component: {
                            name: 'kb-style-pager',
                            params: { totalPages: totalPages() }
                        } -->
                        <!-- /ko -->
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <div class="page-buttons">
        <div class="btn-group dropup">
            <button data-bind="click: onSaveAndReturn" class="btn green" style="margin:0;">Save & Return</button>
            <a class="btn green dropdown-toggle" data-toggle="dropdown" style="margin:0;min-width:auto;"><i class="fa fa-angle-up"></i></a>
            <ul class="dropdown-menu" role="menu">
                <li><a data-bind="click: onSave" href="javascript:;">Save</a></li>
            </ul>
        </div>
        <a data-bind="click: userCancel" class="btn gray">Cancel</a>
    </div>
    <div data-bind="component: { name: 'kb-style-script', params: styleDialogData }"></div>
    <kb-media-dialog params="data: mediaDialogData"></kb-media-dialog>
    <div data-bind="modal: ruleRelationModal" class="modal fade" data-backdrop="static" data-keyboard="false">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button data-bind="click: hideRuleRelationModal" class="close"><i class="fa fa-close"></i></button>
                    <h4 class="modal-title">Relations</h4>
                </div>
                <div class="modal-body">
                    <table class="table table-striped table-hover">
                        <thead>
                            <tr>
                                <th>Page name</th>
                                <th>Page url</th>
                                <th>Relative tag</th>
                            </tr>
                        </thead>
                        <!-- ko if: relations().length -->
                        <tbody data-bind="foreach: relations">
                            <tr>
                                <td data-bind="text: displayName"></td>
                                <td data-bind="text: url"></td>
                                <td data-bind="text: elementName"></td>
                            </tr>
                        </tbody>
                        <!-- /ko -->
                        <!-- ko ifnot: relations().length -->
                        <tbody>
                            <tr>
                                <td class="text-center" colspan="3">No relation</td>
                            </tr>
                        </tbody>
                        <!-- /ko -->
                    </table>
                </div>
                <div class="modal-footer">
                    <button data-bind="click: hideRuleRelationModal" class="btn btn-default">OK</button>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    require([
        "lodash",
        "knockout",
        "kooboo/Guid",
        "jsbeautify",
        "kobindings",
        "kooboo/EventBus",
        "kobindings.codemirror",
        "codemirror/mode/css/css",
        "styleEditor/components/kb-style-set",
        "styleEditor/components/kb-style-pager",
        "components/kb-media-dialog",
        "components/kbStyleScript",
        "domReady!"
    ], function(_, ko, Guid, beautifier) {

        const COUNT = 50;

        var objectNameInvalid = "";
        var i = $("<i>");
        $(i).html(Kooboo.text.validation.objectNameInvalid);
        objectNameInvalid = $(i).text();

        Kooboo.EventBus.subscribe("ko/style/list/relation/show", function(id) {

            Kooboo.CSSRule.getRelation({
                Id: id
            }).then(function(res) {

                if (res.success) {
                    vm.ruleRelationModal(true);
                    vm.relations(res.model);
                }
            });
        })

        Kooboo.EventBus.subscribe("ko/style/list/pickimage/show", function(ctx) {

            Kooboo.Media.getList().then(function(res) {

                if (res.success) {
                    res.model["show"] = true;
                    res.model["context"] = ctx;
                    vm.mediaDialogData(res.model);
                }
            });
        });

        Kooboo.EventBus.subscribe("ko/import/list/pickstyle/show", function(target) {

            var ctx = target.current,
                parent = target.parent,
                used = [vm.fullUrl()];

            _.forEach(parent.importRules(), function(rule) {
                var importUrl = rule.importUrl().match(/url\(["|']?([\S]*[^"|'])["|']?\)/);
                importUrl && used.push(importUrl[1]);
            })

            vm.styleDialogData({
                type: "style",
                used: used,
                show: true,
                context: ctx
            });
        })

        Kooboo.EventBus.subscribe("ko/style/script/selected", function(target) {
            target.context.importUrl('url("' + target.value + '")');
        });

        Kooboo.EventBus.subscribe("kb/style/pager/change", function(page) {
            $(".sp-container.sp-hidden.sp-light.sp-alpha-enabled.sp-clear-enabled.sp-palette-buttons-disabled.sp-initial-disabled").remove();
            vm.changePage(page);
        })

        var styleViewModel = function() {

            var self = this;

            this.isNewStyle = ko.observable(false);
            this.styleId = ko.observable("");

            this.curType = ko.observable("raw");
            this.curType.subscribe(function(type) {

                if (type == "raw") {

                    Kooboo.Style.Get({
                        Id: self.styleId()
                    }).then(function(res) {

                        if (res.success) {

                            self.styleContent(res.model.body || "");
                            self.compareTarget(self.styleContent());
                        }
                    });

                } else {
                    Kooboo.Style.GetRules({
                        id: self.styleId(),
                    }).then(function(res) {

                        if (res.success) {

                            self.allRules(res.model);
                            self.totalPages(Math.ceil(res.model.length / COUNT));
                            self.rules(self.getRulesByPage());
                            self.getModifiedRules(undefined);
                        }
                    })
                }
            });

            this.changeType = function(type) {
                // Kooboo.EventBus.publish("ko/style/list/get");

                if (type == "raw") {

                    if (self.isRulesChanged()) {

                        if (confirm(Kooboo.text.confirm.beforeSwitchPanel)) {
                            self.onSubmitStyle(function() {
                                self.curType(type);
                                self.totalChanges = [];
                            })
                        }
                    } else {

                        self.curType(type);
                    }
                } else {

                    if (!self.isNewStyle()) {
                        if (self.isContentChanged()) {

                            if (confirm(Kooboo.text.confirm.beforeSwitchPanel)) {
                                self.onSubmitStyle(function(id) {
                                    self.isNewStyle(false);
                                    self.styleId(id);
                                    self.curType(type);
                                    self.compareTarget(self.styleContent());
                                });
                            }
                        } else {
                            self.curType(type);
                        }
                    } else {
                        self.onSave(true);
                    }
                }
            }

            this.getRulesByPage = function(page) {
                return _.slice(self.allRules(), page ? page * COUNT : 0, page ? COUNT * (page + 1) : COUNT);
            }

            this.name = ko.validateField({
                required: Kooboo.text.validation.required,
                regex: {
                    pattern: /^[^#\\\./:\*\?\"<>\|~ ]{1}[^\\/:\*\?\"<>\|~ ]{0,254}$/,
                    message: objectNameInvalid
                },
                remote: {
                    url: Kooboo.Style.isUniqueName(),
                    data: {
                        name: function() {
                            return self.name()
                        }
                    },
                    message: Kooboo.text.validation.taken
                }
            });

            this.styleContent = ko.observable("");
            this.compareTarget = ko.observable("");

            this.fullUrl = ko.observable();

            this.formatCode = function() {
                var formatted = beautifier.css_beautify(self.styleContent());
                self.styleContent(formatted);
            }

            this.allRules = ko.observableArray();

            this.totalChanges = [];

            this.totalPages = ko.observable();
            this.changePage = function(page) {
                self.totalChanges.push(self.getRuleChanges());
                self.getModifiedRules(undefined);
                self.rules(self.getRulesByPage(page));
                $(".tab-pane.active")[0].scrollTop = 0;
            }

            this.rules = ko.observableArray([]);
            this._compareRules = ko.observableArray([]);
            this._targetRules = ko.observableArray([]);

            this.showError = ko.observable(false);

            this.isValid = function() {
                return self.name.isValid();
            }

            this.onSubmitStyle = function(callback) {

                if (self.curType() == 'raw') {

                    if ((self.isNewStyle() && self.isValid()) || !self.isNewStyle()) {

                        self.showError(false);

                        Kooboo.Style.Update({
                            id: self.isNewStyle() ? Guid.Empty : self.styleId(),
                            name: self.name(),
                            body: self.styleContent()
                        }).then(function(res) {

                            if (res.success) {

                                if (typeof callback == "function") {
                                    callback(res.model);
                                }
                            } else {
                                window.info.show(Kooboo.text.info.save.fail, false);
                            }
                        });

                    } else {
                        self.showError(true);
                    }
                } else {

                    if (self.isRulesChanged()) {

                        Kooboo.Style.UpdateRules(self.getFlattenChanges())
                            .then(function(res) {

                                if (res.success) {

                                    if (typeof callback === "function") {
                                        callback(res.model);
                                    }
                                }
                            });
                    } else {
                        callback();
                    }
                }
            }

            this.onSaveAndReturn = function() {
                self.onSubmitStyle(function() {
                    self.goBack();
                });
            }

            this.onSave = function(toFormatted) {
                self.onSubmitStyle(function(id) {
                    if (self.isNewStyle()) {
                        location.href = Kooboo.Route.Get(Kooboo.Route.Style.DetailPage, {
                            Id: id
                        }) + (toFormatted ? "#formatted" : "");
                    } else {
                        window.info.show(Kooboo.text.info.save.success, true);
                        self.compareTarget(self.styleContent());
                        self._compareRules(vm.rules());
                        self.getModifiedRules(undefined);
                        self.totalChanges = [];
                    }
                });
            }

            this.userCancel = function() {

                if (self.isContentChanged() || self.isRulesChanged()) {

                    if (confirm(Kooboo.text.confirm.beforeReturn)) {
                        self.goBack();
                    }
                } else {
                    self.goBack();
                }
            }

            this.isContentChanged = function() {
                return self.styleContent() !== self.compareTarget();
            }

            this.getModifiedRules = ko.observable();

            this.isRulesChanged = function() {

                self.totalChanges.push(self.getRuleChanges());

                var result = self.getFlattenChanges();

                return _.keys(result.added).length !== 0 ||
                    _.keys(result.modified).length !== 0 ||
                    result.removed.length !== 0;
            }

            this.getRuleChanges = function() {

                var origRules = _.cloneDeep(self.rules()),
                    modifiedRules = _.cloneDeep(self.getModifiedRules());

                var update = {
                    id: self.styleId(),
                    added: {},
                    modified: {},
                    removed: []
                }

                if (modifiedRules) {

                    _.forEach(origRules, function(or) {

                        var _find = _.findLast(modifiedRules, function(mr) {
                            return mr.id == or.id;
                        });

                        if (_find) {

                            if (self.isModified(or, _find)) {
                                update.modified[_find.id] = _find;
                            }

                            _.remove(modifiedRules, function(mr) {
                                return mr.id == _find.id;
                            })
                        } else {
                            update.removed.push(or.id);
                        }
                    });

                    _.forEach(modifiedRules, function(mr, idx) {
                        update.added[idx] = mr;
                    })

                }

                return update;
            }

            this.isModified = function(src, trg) {

                if (src.selector !== trg.selector) {
                    return true;
                }

                if (src.declarations && trg.declarations) {

                    if (src.declarations.length !== trg.declarations.length) {
                        return true;
                    } else {
                        var modified = false;
                        _.forEach(src.declarations, function(sd) {
                            var _find = _.find(trg.declarations, function(td) {
                                return sd.name == td.name &&
                                    _.trim(sd.value) == _.trim(td.value) &&
                                    sd.important == td.important;
                            });

                            modified = modified || !_find;
                        });

                        return modified;
                    }
                } else {
                    return !_.isEqual(src, trg);
                }
            }

            this.getFlattenChanges = function() {
                var added = {},
                    modified = {},
                    removed = [];

                _.forEach(self.totalChanges, function(change) {
                    debugger;
                    _.forEach(_.keys(change.added), function(key) {
                        added[key] = change.added[key];
                    })

                    _.forEach(_.keys(change.modified), function(key) {
                        modified[key] = change.modified[key];
                    })

                    _.forEach(change.removed, function(rm) {
                        removed.push(rm);
                    });
                })

                return {
                    added: added,
                    modified: modified,
                    removed: removed,
                    id: styleId
                }
            }

            this.goBack = function() {
                location.href = Kooboo.Route.Get(Kooboo.Route.Style.ListPage);
            }

            this.mediaDialogData = ko.observable();

            this.styleDialogData = ko.observable();

            // Relation modal
            this.ruleRelationModal = ko.observable(false);

            this.relations = ko.observableArray();

            this.hideRuleRelationModal = function() {
                self.ruleRelationModal(false);
                self.relations([]);
            };
        };

        var vm = new styleViewModel();

        var styleId = Kooboo.getQueryString("Id");

        if (styleId) {
            vm.isNewStyle(false);
            vm.styleId(styleId);
            Kooboo.Style.GetEdit({
                Id: styleId
            }).then(function(res) {

                if (res.success) {
                    vm.name(res.model.displayName);
                    vm.styleContent(res.model.body || "");
                    vm.fullUrl(res.model.fullUrl || "");
                    vm.compareTarget(vm.styleContent());

                    if (location.hash.split("#")[1] == "formatted") {
                        vm.curType("fmt");
                    }
                }
            })
        } else {
            vm.isNewStyle(true);
        }

        ko.applyBindings(vm, document.getElementById("main"));
    });
</script>